#include "sysInit.h"
#include "sample_comm.h"
#include "vo_sdi.h"
#include "vo_cvbs.h"
#include <unistd.h>

typedef struct {
    ot_size            max_size;
    ot_pixel_format    pixel_format;
    ot_size            output_size[OT_VPSS_MAX_PHYS_CHN_NUM];
    ot_compress_mode   compress_mode[OT_VPSS_MAX_PHYS_CHN_NUM];
    td_bool            enable[OT_VPSS_MAX_PHYS_CHN_NUM];
} sample_venc_vpss_chn_attr;

typedef struct {
    td_u32 valid_num;
    td_u64 blk_size[OT_VB_MAX_COMMON_POOLS];
    td_u32 blk_cnt[OT_VB_MAX_COMMON_POOLS];
    td_u32 supplement_config;
} sample_venc_vb_attr;

typedef struct {
    ot_vpss_chn vpss_chn[CHN_NUM_MAX];
    ot_venc_chn venc_chn[CHN_NUM_MAX];
} sample_venc_vpss_chn;

#define BIG_STREAM_SIZE         PIC_3840X2160
#define SMALL_STREAM_SIZE       PIC_1080P

#define VI_VB_YUV_CNT           6
#define VPSS_VB_YUV_CNT         8

static td_bool g_sample_venc_exit = TD_FALSE;

static td_void get_default_vpss_chn_attr(ot_size *vi_size, ot_size enc_size[], td_s32 len,
    sample_venc_vpss_chn_attr *vpss_chn_attr)
{
    td_s32 i;
    td_u32 max_width;
    td_u32 max_height;

    if (memset_s(vpss_chn_attr, sizeof(sample_venc_vpss_chn_attr), 0, sizeof(sample_venc_vpss_chn_attr)) != EOK) {
        printf("vpss chn attr call memset_s error\n");
        return;
    }

    max_width = vi_size->width;
    max_height = vi_size->height;

    for (i = 0; (i < len) && (i < OT_VPSS_MAX_PHYS_CHN_NUM); i++) {

        vpss_chn_attr->output_size[i].width = (i == 3) ? 1920:enc_size[i].width;
        vpss_chn_attr->output_size[i].height = (i == 3) ? 1080:enc_size[i].height;
    //    vpss_chn_attr->compress_mode[i] = (i == 0) ? OT_COMPRESS_MODE_SEG_COMPACT : OT_COMPRESS_MODE_NONE;
        vpss_chn_attr->compress_mode[i] = OT_COMPRESS_MODE_NONE;
        vpss_chn_attr->enable[i] = TD_TRUE;
        

        max_width = MAX2(max_width, enc_size[i].width);
        max_height = MAX2(max_height, enc_size[i].height);
    }

    vpss_chn_attr->max_size.width = max_width;
    vpss_chn_attr->max_size.height = max_height;
    vpss_chn_attr->pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420;

    return;
}

static td_s32 sample_venc_init_param(ot_size *enc_size, td_s32 chn_num_max, ot_size *vi_size,
    sample_venc_vpss_chn_attr *vpss_param)
{
    td_s32 i;
    td_s32 ret;
    ot_pic_size pic_size[CHN_NUM_MAX] = {BIG_STREAM_SIZE,BIG_STREAM_SIZE,BIG_STREAM_SIZE,BIG_STREAM_SIZE};

    for (i = 0; i < chn_num_max && i < CHN_NUM_MAX; i++) {
        ret = sample_comm_sys_get_pic_size(pic_size[i], &enc_size[i]);
        if (ret != TD_SUCCESS) {
            sample_print("sample_comm_sys_get_pic_size failed!\n");
            return ret;
        }
    }

    // get vpss param
    get_default_vpss_chn_attr(vi_size, enc_size, CHN_NUM_MAX, vpss_param);

    return 0;
}

static td_void get_vb_attr(const ot_size *vi_size, const sample_venc_vpss_chn_attr *vpss_chn_attr,
    sample_venc_vb_attr *vb_attr)
{
    td_s32 i;
    ot_pic_buf_attr pic_buf_attr = {};

    vb_attr->valid_num = 0;

    // vb for vi-vpss
    pic_buf_attr.width  = vi_size->width;
    pic_buf_attr.height = vi_size->height;
    pic_buf_attr.align = OT_DEFAULT_ALIGN;
    pic_buf_attr.bit_width = OT_DATA_BIT_WIDTH_8;
    pic_buf_attr.pixel_format = OT_PIXEL_FORMAT_YUV_SEMIPLANAR_420;
    pic_buf_attr.compress_mode = OT_COMPRESS_MODE_NONE;
    vb_attr->blk_size[vb_attr->valid_num] = ot_common_get_pic_buf_size(&pic_buf_attr);
    vb_attr->blk_cnt[vb_attr->valid_num] = VI_VB_YUV_CNT;
    vb_attr->valid_num++;

    // vb for vpss-venc(big stream)
    if (vb_attr->valid_num >= OT_VB_MAX_COMMON_POOLS) {
        return;
    }

    for (i = 0; i < OT_VPSS_MAX_PHYS_CHN_NUM && vb_attr->valid_num < OT_VB_MAX_COMMON_POOLS; i++) {
        if (vpss_chn_attr->enable[i] == TD_TRUE) {
            pic_buf_attr.width = vpss_chn_attr->output_size[i].width;
            pic_buf_attr.height = vpss_chn_attr->output_size[i].height;
            pic_buf_attr.align = OT_DEFAULT_ALIGN;
            pic_buf_attr.bit_width = OT_DATA_BIT_WIDTH_8;
            pic_buf_attr.pixel_format = vpss_chn_attr->pixel_format;
            pic_buf_attr.compress_mode = vpss_chn_attr->compress_mode[i];
            if (pic_buf_attr.compress_mode == OT_COMPRESS_MODE_SEG_COMPACT) {
                ot_vb_calc_cfg calc_cfg = {};
                ot_common_get_vpss_compact_seg_buf_size(&pic_buf_attr, &calc_cfg);
                vb_attr->blk_size[vb_attr->valid_num] = calc_cfg.vb_size;
            } else {
                vb_attr->blk_size[vb_attr->valid_num] = ot_common_get_pic_buf_size(&pic_buf_attr);
            }
            vb_attr->blk_cnt[vb_attr->valid_num] = VPSS_VB_YUV_CNT;

            vb_attr->valid_num++;
        }
    }

    vb_attr->supplement_config = OT_VB_SUPPLEMENT_JPEG_MASK | OT_VB_SUPPLEMENT_BNR_MOT_MASK;
}

static td_s32 ss_sys_init(sample_venc_vb_attr *vb_attr)
{
    td_u32 i;
    td_s32 ret;
    ot_vb_cfg vb_cfg = {};

    if (vb_attr->valid_num > OT_VB_MAX_COMMON_POOLS) {
        INFO_PRT("ss_sys_init vb valid num(%d) too large than OT_VB_MAX_COMMON_POOLS(%d)!\n",
            vb_attr->valid_num, OT_VB_MAX_COMMON_POOLS);
        return TD_FAILURE;
    }

    for (i = 0; i < vb_attr->valid_num; i++) {
        vb_cfg.common_pool[i].blk_size = vb_attr->blk_size[i];
        vb_cfg.common_pool[i].blk_cnt = vb_attr->blk_cnt[i];
    }

    vb_cfg.max_pool_cnt = vb_attr->valid_num;

    if (vb_attr->supplement_config == 0) {
        ret = sample_comm_sys_init(&vb_cfg);
    } else {
        ret = sample_comm_sys_init_with_vb_supplement(&vb_cfg, vb_attr->supplement_config);
    }

    if (ret != TD_SUCCESS) {
        INFO_PRT("ss_sys_init failed!\n");
    }

    return ret;
}


static td_s32 ss_vi_init(sample_vi_cfg *vi_cfg)
{
    td_s32 ret;

    ret = sample_comm_vi_start_vi(vi_cfg);
    if (ret != TD_SUCCESS) {
        ERRO_PRT("sample_comm_vi_start_vi failed: 0x%x\n", ret);
        return ret;
    }

    return TD_SUCCESS;
}

static td_s32 ss_vpss_init(ot_vpss_grp vpss_grp, sample_venc_vpss_chn_attr *vpss_chn_cfg)
{
    td_s32 ret;
    ot_vpss_chn vpss_chn;
    ot_vpss_grp_attr grp_attr = {};
    ot_vpss_chn_attr chn_attr[OT_VPSS_MAX_PHYS_CHN_NUM] = {};

    grp_attr.max_width = vpss_chn_cfg->max_size.width;
    grp_attr.max_height = vpss_chn_cfg->max_size.height;
    grp_attr.nr_en = TD_FALSE;
    grp_attr.dei_mode = OT_VPSS_DEI_MODE_OFF;
    grp_attr.pixel_format = vpss_chn_cfg->pixel_format;
    grp_attr.frame_rate.src_frame_rate = -1;
    grp_attr.frame_rate.dst_frame_rate = -1;

    td_u32 max_chn_width = 0,max_chn_height = 0;
    for (vpss_chn = 0; vpss_chn < OT_VPSS_MAX_PHYS_CHN_NUM; vpss_chn++) {
        if (vpss_chn_cfg->enable[vpss_chn] == 1) {
            chn_attr[vpss_chn].width = vpss_chn_cfg->output_size[vpss_chn].width;
            chn_attr[vpss_chn].height = vpss_chn_cfg->output_size[vpss_chn].height;
            chn_attr[vpss_chn].chn_mode = OT_VPSS_CHN_MODE_USER;
            chn_attr[vpss_chn].compress_mode = vpss_chn_cfg->compress_mode[vpss_chn];
            chn_attr[vpss_chn].pixel_format = vpss_chn_cfg->pixel_format;
            chn_attr[vpss_chn].frame_rate.src_frame_rate = -1;
            chn_attr[vpss_chn].frame_rate.dst_frame_rate = -1;
            chn_attr[vpss_chn].depth = TD_FALSE;
            chn_attr[vpss_chn].mirror_en = TD_FALSE;
            chn_attr[vpss_chn].flip_en = TD_FALSE;
            chn_attr[vpss_chn].aspect_ratio.mode = OT_ASPECT_RATIO_NONE;

            max_chn_width  = MAX2(max_chn_width,chn_attr[vpss_chn].width);
            max_chn_height = MAX2(max_chn_height,chn_attr[vpss_chn].height);
        }
    }
    // 临时设置vpss 0 chn2 为1280*1024
    
    chn_attr[2].width = VPSS_CHN2_IMAGE_WIDTH;
    chn_attr[2].height = VPSS_CHN2_IMAGE_HEIGHT;
    chn_attr[2].pixel_format = OT_PIXEL_FORMAT_YUV_400;

    ret = sample_common_vpss_start(VIS_VPSS_GRP_ID, vpss_chn_cfg->enable, &grp_attr, chn_attr, OT_VPSS_MAX_PHYS_CHN_NUM);
    if (ret != TD_SUCCESS) {
        ERRO_PRT("failed with %#x!\n", ret);
    }

    int crop_width = (grp_attr.max_width - max_chn_width)/2;
    int crop_height = (grp_attr.max_height - max_chn_height)/2;

    ot_vpss_crop_info vpss_crop_info;
    vpss_crop_info.enable = TD_TRUE;
    vpss_crop_info.crop_mode = OT_COORD_ABS;
    vpss_crop_info.crop_rect.x = crop_width;
    vpss_crop_info.crop_rect.y = crop_height;
    vpss_crop_info.crop_rect.width = max_chn_width;
    vpss_crop_info.crop_rect.height = max_chn_height;

    ret = ss_mpi_vpss_set_grp_crop(VIS_VPSS_GRP_ID,&vpss_crop_info);
    if(ret != TD_SUCCESS){
        ERRO_PRT("error ss_mpi_vpss_set_grp_crop %#x,param crop x %d y %d,w %d h %d\n",ret,crop_width,crop_height,max_chn_width,max_chn_height);
    }

    return ret;
}


static td_void sample_venc_exit_process()
{
    printf("please press twice ENTER to exit this sample\n");
    (td_void)getchar();

    if (g_sample_venc_exit != TD_TRUE) {
        (td_void)getchar();
    }
    sample_comm_venc_stop_get_stream(CHN_NUM_MAX);
}

static td_void sample_venc_unbind_vpss_stop(ot_vpss_grp vpss_grp, const sample_venc_vpss_chn *venc_vpss_chn)
{
    td_s32 i;

    for (i = 0; i < CHN_NUM_MAX; i++) {
        sample_comm_vpss_un_bind_venc(vpss_grp, venc_vpss_chn->vpss_chn[i], venc_vpss_chn->venc_chn[i]);
        sample_comm_venc_stop(venc_vpss_chn->venc_chn[i]);
    }
}


static td_void sample_venc_vpss_deinit(ot_vpss_grp vpss_grp, sample_venc_vpss_chn_attr *vpss_chn_cfg)
{
    td_s32 ret;

    ret = sample_common_vpss_stop(vpss_grp, vpss_chn_cfg->enable, OT_VPSS_MAX_PHYS_CHN_NUM);
    if (ret != TD_SUCCESS) {
        sample_print("failed with %#x!\n", ret);
    }
}

static td_void sample_venc_vi_deinit(sample_vi_cfg *vi_cfg)
{
    sample_comm_vi_stop_vi(vi_cfg);
}

int ss928_sys_init()
{
    td_s32 ret = 0;
    sample_sns_type sns_type = SENSOR0_TYPE;
    sample_vi_cfg vi_cfg;
    ot_size enc_size[CHN_NUM_MAX];
    
    sample_venc_vpss_chn_attr vpss_param;
    sample_venc_vb_attr vb_attr = {};
    sample_venc_vpss_chn venc_vpss_chn = {};

    for (int i = 0; i < CHN_NUM_MAX; i++) {
        venc_vpss_chn.vpss_chn[i] = i;
        venc_vpss_chn.venc_chn[i] = i;
    }

    
    sample_comm_vi_get_default_vi_cfg(sns_type, &vi_cfg);

    
    /******************************************
      step 0: related parameter ready
    ******************************************/
    ret = sample_venc_init_param(enc_size, CHN_NUM_MAX, &(vi_cfg.dev_info.dev_attr.in_size), &vpss_param);
    if (ret != TD_SUCCESS) {
        return ret;
    }

    /******************************************
      step 1: init sys alloc common vb
    ******************************************/
    get_vb_attr(&(vi_cfg.dev_info.dev_attr.in_size), &vpss_param, &vb_attr);

    if ((ret = ss_sys_init(&vb_attr)) != TD_SUCCESS) {
        sample_print("Init SYS err for %#x!\n", ret);
        return ret;
    }

    if ((ret = ss_vi_init(&vi_cfg)) != TD_SUCCESS) {
        sample_print("Init VI err for %#x!\n", ret);
        goto EXIT_SYS_STOP;
    }

    if ((ret = ss_vpss_init(VIS_VPSS_GRP_ID, &vpss_param)) != TD_SUCCESS) {
        sample_print("Init VPSS err for %#x!\n", ret);
        goto EXIT_VI_STOP;
    }

    if ((ret = sample_comm_vi_bind_vpss(VIS_MIPI_VI_PIPE, VIS_MIPI_VI_CHN, VIS_VPSS_GRP_ID, 0)) != TD_SUCCESS) {
        sample_print("VI Bind VPSS err for %#x!\n", ret);
        goto EXIT_VPSS_STOP;
    }

    if(vo_sdi_sys_init() != TD_SUCCESS){
        goto EXIT_VPSS_STOP; 
    }

    if(vo_cvbs_sys_init() != TD_SUCCESS){
        goto EXIT_VPSS_STOP; 
    }
    

    return ret;
   
    // if ((ret = sample_venc_normal_start_encode(VPSS_GRP_ID, &venc_vpss_chn)) != TD_SUCCESS) {
    //     goto EXIT_VI_VPSS_UNBIND;
    // }

    /******************************************
     exit process
    ******************************************/
    sample_venc_exit_process();
    sample_venc_unbind_vpss_stop(VIS_VPSS_GRP_ID, &venc_vpss_chn);

    // EXIT_VI_VPSS_UNBIND:
    sample_comm_vi_un_bind_vpss(VIS_MIPI_VI_PIPE, VIS_MIPI_VI_CHN, VIS_VPSS_GRP_ID, 0);
EXIT_VPSS_STOP:
    sample_venc_vpss_deinit(VIS_VPSS_GRP_ID, &vpss_param);
EXIT_VI_STOP:
    sample_venc_vi_deinit(&vi_cfg);
EXIT_SYS_STOP:
    sample_comm_sys_exit();

    return 0;
}

int ss928_sys_destory()
{

//    sample_venc_vpss_chn venc_vpss_chn = {};
    sample_venc_vpss_chn_attr vpss_param = {};
    

    for (int i = 0; i < CHN_NUM_MAX; i++) {
        // venc_vpss_chn.vpss_chn[i] = i;
        // venc_vpss_chn.venc_chn[i] = i;

        vpss_param.enable[i] = TD_TRUE;
    }

    sample_vi_cfg vi_cfg;
    sample_comm_vi_get_default_vi_cfg(SENSOR0_TYPE, &vi_cfg);
    
    
    

    // EXIT_VI_VPSS_UNBIND:
    sample_comm_vi_un_bind_vpss(VIS_MIPI_VI_PIPE, VIS_MIPI_VI_CHN, VIS_VPSS_GRP_ID, 0);

    sample_venc_vpss_deinit(VIS_VPSS_GRP_ID, &vpss_param);

    sample_venc_vi_deinit(&vi_cfg);

    sample_comm_sys_exit();

    return 0;
 
}